package com.roncoo.education.oauth.config;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
 
/**
 * @author 千城丶Y
 * @className : JdbcAuthorizationServerConfig
 * @PACKAGE_NAME : com.bjpowenrode.oauth.config
 * @date : 2022/9/21 23:17
 * @Description TODO 基于JWT令牌的 授权服务器配置
 */
@Configuration
@EnableAuthorizationServer
public class JWTAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
 
    private final AuthenticationManager authenticationManager ;
    private final PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
 
    @Autowired
    private ClientDetailsServiceImpl clientDetailsService;
	@Autowired
    private CustomerTokenEnhancer tokenEnhancer;
	@Autowired
	private UserDetailsService userDetailsService;
//    @Autowired
//    private JwtAccessTokenConverter jwtAccessTokenConverter;	
    
    public JWTAuthorizationServerConfig(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
    }
 
    /**
     * 声明基于jwt实现令牌的存储方式
     */
    @Bean
    public TokenStore tokenStore() {
        return  new JwtTokenStore(jwtAccessTokenConverter());
    }
 
    /**
     * 声明 基于数据库实现的ClientDetails 用于存储和查询客户端信息和令牌
     */
//    @Bean
//    public ClientDetailsService detailsService (){
//        JdbcClientDetailsService jdbcClientDetailsService = new JdbcClientDetailsService(dataSource);
//        jdbcClientDetailsService.setPasswordEncoder(passwordEncoder); // 用于加密和解密  密钥
//        return jdbcClientDetailsService;
//    }
 
    /**
     *  配置使用基于 jwt 方式颁发令牌，同时配置 jwt转换器
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(tokenStore())
                .accessTokenConverter(jwtAccessTokenConverter())
                .authenticationManager(authenticationManager);
        
        endpoints.userDetailsService(userDetailsService); // 开启刷新令牌必现指定
        endpoints.authenticationManager(authenticationManager); // 密码模式需要注入 authenticationManager
        
//        endpoints.tokenStore(tokenStore);
//        endpoints.accessTokenConverter(jwtAccessTokenConverter);
        
        TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
        List<TokenEnhancer> list = new ArrayList<>();
        list.add(tokenEnhancer);
        list.add(jwtAccessTokenConverter());
        tokenEnhancerChain.setTokenEnhancers(list);
        endpoints.tokenEnhancer(tokenEnhancerChain);
        
//        endpoints.exceptionTranslator(new WebResponseExceptionTranslator() {
//            public ResponseEntity translate(Exception e) throws Exception {
//                if (e instanceof OAuth2Exception) {
//                    int code = 888;
//                    String message = "fsdafsa";
//                    return ResponseEntity.ok("fads");
//                }
//                throw e;
//            }
//        });
    }
    // 使用同一个密钥来编码 JWT OAuth2 令牌
    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter() {
        JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
        jwtAccessTokenConverter.setSigningKey("123"); // 可以采用属性注入方式，生产中建议加密 ，密钥的key 很重要
        return jwtAccessTokenConverter;
    }
    
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.withClientDetails(clientDetailsService); // 使用JDBC存储
    	
//        clients
//        .inMemory() // 表示基于内存
//        .withClient("clientId" ) // 设置客户端编号
//        .secret(passwordEncoder.encode("123456")) // 设置客户端密钥 ,这里官方规定secret必现加密 可以使用 passwordEncode
//        .redirectUris("http://www.baidu.com") // 重定向URI
//        // authorization_code 授权码   refresh_token 刷新令牌  implicit 简化模式   password 密码模式  client_credentials 客户端模式
//        // 暂不支持简化模式, 因为需要解析一段脚本来获取令牌
//        .authorizedGrantTypes("authorization_code","refresh_token","implicit","password","client_credentials") // 表示使用那种授权模式 可以设置支持多种，授权码模式
//        // 拥有的权限     
//        .scopes("callback:score");// 令牌允许获取资源权限
    }
}
